﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Castle.Core.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using User.EF.Model;
using User.Global.Contracts.Membership;
using User.Global.Contracts.Message;
using User.Global.Tests.Helper.Common;
using User.Web.Common.WebAttributes;
using User.Web.Models.Account;

namespace User.Web.UI.Tests.Unit.ModelTests
{
    /// <summary>
    /// Die Tests für das RegisterModel
    /// </summary>
    [TestClass]
    public class RegisterModelTest
    {
        #region Method Tests
        /// <summary>
        /// Prüft ob die Funktion CreateUser funktioniert hat.
        /// </summary>
        [TestMethod]
        public void CreateUser_Success()
        {
            RegisterModel registerModel = new RegisterModel();
            registerModel.Username = "squadwuschel";
            registerModel.Password = "testpasswort";

            Mock<IDiMembership<Member>> mockMembership = new Mock<IDiMembership<Member>>();
            //It.IsAny<Obj> Gibt an das es sich nicht um ein bestimmtes Member Objekt handeln muss, was z.B. per DI übergeben wurde
            //sondern einfach irgendein Member Objekt
            mockMembership.Setup(p => p.CreateUser("squadwuschel", "testpasswort", It.IsAny<Member>())).Returns(true);

            //Assert
            Assert.IsTrue(registerModel.CreateUser(mockMembership.Object));
            mockMembership.Verify(p => p.CreateUser("squadwuschel", "testpasswort", It.IsAny<Member>()), Times.Once);
        }

        /// <summary>
        /// Prüft ob die Funktion CreateUser nicht funktioniert hat.
        /// </summary>
        [TestMethod]
        public void CreateUser_Failed()
        {
            RegisterModel registerModel = new RegisterModel();

            Mock<IDiMembership<Member>> mockMembership = new Mock<IDiMembership<Member>>();
            mockMembership.Setup(p => p.CreateUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Member>())).Returns(false);

            //Assert
            Assert.IsFalse(registerModel.CreateUser(mockMembership.Object));
            mockMembership.Verify(p => p.CreateUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Member>()), Times.Once);
        }

        /// <summary>
        /// Prüft ob eine NullReferenceException geworfen wird, wenn als AddMessage Null übergeben wird.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException), "AddMessage is Null")]
        public void SetCommunications_ExceptionAddMessage_IsNull()
        {
            RegisterModel registerModel = new RegisterModel();
            registerModel.SetCommunication(new ConsoleLogger(), null);
        }

        /// <summary>
        /// Prüft ob eine NullReferenceException geworfen wird, wenn als AddMessage Null übergeben wird.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException), "Logger is Null")]
        public void SetCommunications_ExceptionLogger_IsNull()
        {
            Mock<IAddMessage> mockMessage = new Mock<IAddMessage>();

            RegisterModel registerModel = new RegisterModel();
            registerModel.SetCommunication(null,mockMessage.Object);
        }
        #endregion

        #region Property Tests
        /// <summary>
        /// Prüft ob alle wichtigen Attribute des Passwort Properties
        /// </summary>
        [TestMethod]
        public void Attribute_CheckForProperty_Password()
        {
            //Sucht alle Properties unseres Models heraus.
            PropertyInfo propertyInfo = typeof(RegisterModel).GetProperty("Password");
            Assert.IsTrue(propertyInfo.HasDataType(DataType.Password));
            Assert.IsTrue(propertyInfo.HasAttribute<RequiredAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<DisplayAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<HtmlAttributesAttribute>());
        }

        /// <summary>
        /// Prüft ob alle wichtigen Attribute des ConfirmPassword Properties
        /// </summary>
        [TestMethod]
        public void Attribute_CheckForProperty_ConfirmPassword()
        {
            //Sucht alle Properties unseres Models heraus.
            PropertyInfo propertyInfo = typeof(RegisterModel).GetProperty("ConfirmPassword");
            Assert.IsTrue(propertyInfo.HasDataType(DataType.Password));
            Assert.IsTrue(propertyInfo.HasAttribute<RequiredAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<DisplayAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<HtmlAttributesAttribute>());
        }

        /// <summary>
        /// Prüft ob alle wichtigen Attribute des Username Properties
        /// </summary>
        [TestMethod]
        public void Attribute_CheckForProperty_Username()
        {
            //Sucht alle Properties unseres Models heraus.
            PropertyInfo propertyInfo = typeof(RegisterModel).GetProperty("Username");
            Assert.IsTrue(propertyInfo.HasDataType(DataType.EmailAddress));
            Assert.IsTrue(propertyInfo.HasAttribute<RequiredAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<DisplayAttribute>());
            Assert.IsTrue(propertyInfo.HasAttribute<HtmlAttributesAttribute>());
        }
        #endregion
    }
}
